//
// Created by tongj on 2023/10/19.
//

#ifndef TBS_CPP_LISTENER_H
#define TBS_CPP_LISTENER_H

#include <base/base.hpp>

template<class P, class... ARGS> using beforeConsume = std::function<void(P* obj, ARGS... args)>;

template<class P, class R, class... ARGS> using afterConsume = std::function<void(P* obj, REF(R, result),
        ARGS... args)>;

/**
 * 对象方法监听
 * @tparam P 对象类型
 * @tparam R 方法返回值
 * @tparam ARGS 方法参数
 */
template<class P, class R, P* _val, class... ARGS> class Listener
{
public:
    using l_method = R (P::*)(ARGS...);
    using l_before = beforeConsume<P, ARGS...>;
    using l_after = afterConsume<P, R, ARGS...>;
    using self = Listener<P, R, _val, ARGS...>;
    using l_error = std::function<void(P* p, CONST tbs::base_error&, R* re)>;

    /**
     *
     * @param va
     * @param method
     * @param bef
     * @param af
     * @param error
     */
    explicit Listener(l_method method, l_before bef = nullptr, l_after af = nullptr, l_error error = nullptr) NO_EXCEPT
    {
        this->_method = method;
        this->_before = bef;
        this->_after = af;
        this->_error = error;
    }

    /**
     * 设置前置方法
     * @param b
     * @return
     */

    self& before(l_before b) NO_EXCEPT
    {
        this->_before = b;
        return *this;
    }

    /**
     * 设置后置方法
     * @param a
     * @return
     */

    self& after(l_after a) NO_EXCEPT
    {
        this->_after = a;
        return *this;
    }

    /**
     * 设置异常处理方法
     * @param e
     * @return
     */

    self& error(l_error e) NO_EXCEPT
    {
        this->_error = e;
        return *this;
    }

    /**
     * 安全调用方法
     * @param def 默认返回值
     * @param args 调用参数
     * @return 结果
     */

    R safeInvoke(R&& def, ARGS... args) NO_EXCEPT
    {
        try
        {
            return invoke(args...);
        }
        catch (tbs::base_error& e)
        {
            if (this->_error != nullptr)
            {
                this->_error(this->_val, e, &def);
            }
            return def;
        }
    }

    R operator()(ARGS... args)
    {
        return invoke(args...);
    }

    /**
     * 直接调用
     * @param args 调用参数
     * @return
     */
    R invoke(ARGS... args)
    {
        if (_before != nullptr)
        {
            _before(_val, args...);
        }

        auto obj = std::bind(_method, _val, args...);
        R re = obj();

        if (_after != nullptr)
        {
            _after(_val, re, args...);
        }
        return re;
    }

private:
    /**
     * 调用体的方法
     */
    l_method _method = nullptr;
    /**
     * 前置方法
     */
    l_before _before = nullptr;

    /**
     * 后置方法
     */
    l_after _after = nullptr;

    /**
     * 异常处理方法
     */
    l_error _error = nullptr;
};

#define make_listenner()

#endif // TBS_CPP_LISTENER_H
